package com.hjk.common.utils.reflect;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Supplier;

/**
 * 失败重试工具类
 *
 * @author huangjunkai
 * @version 1.0
 * @date 2020/5/29 16:42
 */
@ConfigurationProperties(prefix = "spring.kafka.consumer")
@Configuration
@EnableConfigurationProperties(RetriesUtils_temp.class)
public class RetriesUtils_temp {
    private static final Logger log = LoggerFactory.getLogger(RetriesUtils_temp.class);
    /**
     * 重试次数
     */
    public static final int RETRIES = 3;

    /**
     * 方法执行成功
     */
    public static final String SUCCESS = "success";

    /**
     * 方法执行失败,重试
     */
    public static final String ERROR = "error";


    public static Object retries(String nowResult, Object obj, String methodName, Object[] param) {

        try {
            //执行某个方法的结果比较
            Class[] classes = Arrays.stream(param).map(Object::getClass).toArray(Class[]::new);
            if (ERROR.equals(nowResult)) {
                for (int i = 0; i < RETRIES; i++) {
                    Method method = obj.getClass().getDeclaredMethod(methodName, classes);
                    String result = method.invoke(obj, param).toString();
                    if (RetriesUtils_temp.SUCCESS.equals(result)) {
                        break;
                    }

                }
            }

        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }

    /**
     * 反射调用方法,执行错误则重试
     *
     * @param obj        执行方法的对象
     * @param methodName 方法名
     * @param param      执行方法的参数
     * @param <T>        null
     * @return null
     */

    public static <T> T retriesMethod(Object obj, String methodName, Object[] param) {
        try {
            Class[] classes = Arrays.stream(param).map(Object::getClass).toArray(Class[]::new);
            Method method = obj.getClass().getDeclaredMethod(methodName,classes);
            String result = method.invoke(obj, param).toString();
            //方法执行失败进入重试
            if (ERROR.equals(result)) {
                for (int i = 0; i < RETRIES; i++) {
                    //方法重试
                    log.info("=======方法 {}.{}({})重试中========", obj.getClass().getName(), methodName, param.getClass());
                    String r = method.invoke(obj, param).toString();
                    //执行成功则结束
                    if (RetriesUtils_temp.SUCCESS.equals(r)) {
                        log.info("=======方法 {}.{}({})重试成功========", obj.getClass().getName(), methodName, param.getClass());
                        break;
                    }

                }
            }
        } catch (Exception e) {
            log.error("retriesMethod反射方法执行失败错误", e);
        }
        return null;
    }

    public static String print(String value) {
        try {
            System.out.println(String.format("当前参数值: %s", value));
            if ("500".equals(value)) {
                int i = 1 / 0;
            }
            return SUCCESS;

        } catch (Exception e) {
            log.error("=======[ 反射调用方法失败 ]=======", e.fillInStackTrace());
            return ERROR;
        }
    }


    private static <T> T retriesMethod(int retriesCount, String business, Supplier supplier) {
        try {
            boolean result = (Boolean) supplier.get();
            //方法执行失败进入重试
            if (result) {
                for (int count = 1; count <= retriesCount; count++) {
                    //方法重试
                    log.info("=======方法[{}] 第{}次重试中========", business, count);
                    boolean success = (Boolean) supplier.get();
                    //执行成功则结束
                    if (!success) {
                        log.info("=======方法[{}] 第{}次重试成功========", business, count);
                        break;
                    }

                }
            }
        } catch (Exception e) {
            log.error("=======重试方法[{}]失败错误=======", business, e);
        }
        return null;
    }

    /**
     * 重试方法,默认重试3次
     *
     * @param business 业务类型
     * @param runnable 方法
     */
    public static void execute(String business, Runnable runnable) {
        execute(RETRIES, business, runnable);
    }

    /**
     * 重试方法
     *
     * @param retriesCount 重试次数
     * @param business     业务类型
     * @param runnable     方法
     */
    public static void execute(int retriesCount, String business, Runnable runnable) {
        retriesMethod(retriesCount, business, () -> {
            try {
                runnable.run();
                return false;
            } catch (Exception e) {
                log.error("=======[ 调用方法失败 ]=======", e.fillInStackTrace());
                return true;
            }
        });

    }


    public static void main(String[] args) {
        execute("失败重试", () -> {
            int i = 1 / 0;
        });

        execute("成功转型", () -> {
            System.out.println(1111);
        });

    }

}
